home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / xvisrc.zip / EDIT.C < prev    next >
C/C++ Source or Header  |  1992-07-28  |  14KB  |  623 lines

  1. /* Copyright (c) 1990,1991,1992 Chris and John Downey */
  2. #ifndef lint
  3. static char *sccsid = "@(#)edit.c    2.4 (Chris & John Downey) 8/26/92";
  4. #endif
  5.  
  6. /***
  7.  
  8. * program name:
  9.     xvi
  10. * function:
  11.     PD version of UNIX "vi" editor, with extensions.
  12. * module name:
  13.     edit.c
  14. * module function:
  15.     Insert and replace mode handling.
  16. * history:
  17.     STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  18.     Originally by Tim Thompson (twitch!tjt)
  19.     Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  20.     Heavily modified by Chris & John Downey
  21.  
  22. ***/
  23.  
  24. #include "xvi.h"
  25.  
  26. static    void    end_replace P((int));
  27.  
  28. /*
  29.  * Position of start of insert. This is used
  30.  * to prevent backing up past the starting point.
  31.  */
  32. static    Posn    Insertloc;
  33.  
  34. /*
  35.  * This flexbuf is used to hold the current insertion text.
  36.  */
  37. static    Flexbuf    Insbuff;
  38.  
  39. /*
  40.  * Replace-mode stuff.
  41.  */
  42. static    enum    {
  43.         replace_one,    /* replace command was an 'r' */
  44.         got_one,    /* normal ending state for replace_one */
  45.         overwrite    /* replace command was an 'R' */
  46. }        repstate;
  47.  
  48. static    char    *saved_line;    /*
  49.                  * record of old line before replace
  50.                  * started; note that, if
  51.                  * (repstate != overwrite), this
  52.                  * should never be referenced.
  53.                  */
  54. static    int    nchars;        /* no of chars in saved_line */
  55. static    int    start_index;    /* index into line where we entered replace */
  56. static    int    start_column;    /* virtual col corresponding to start_index */
  57.  
  58. /*
  59.  * Process the given character, in insert mode.
  60.  */
  61. bool_t
  62. i_proc(c)
  63. int    c;
  64. {
  65.     register Posn    *curpos;
  66.     static bool_t    literal_next = FALSE;
  67.     static bool_t    wait_buffer = FALSE;
  68.  
  69.     curpos = curwin->w_cursor;
  70.  
  71.     if (wait_buffer || (!literal_next && c == CTRL('A'))) {
  72.     /*
  73.      * Add contents of named buffer, or the last
  74.      * insert buffer if CTRL('A') was typed.
  75.      */
  76.     if (!wait_buffer) {
  77.         c = '<';
  78.     }
  79.     yp_stuff_input(curwin, c, TRUE);
  80.     wait_buffer = FALSE;
  81.     return(FALSE);
  82.  
  83.     } else if (!literal_next) {
  84.     /*
  85.      * This switch is for special characters; we skip over
  86.      * it for normal characters, or for literal-next mode.
  87.      */
  88.     switch (c) {
  89.     case ESC:    /* an escape ends input mode */
  90.     {
  91.         char    *cltext;
  92.  
  93.         cltext = curpos->p_line->l_text;
  94.  
  95.         curwin->w_set_want_col = TRUE;
  96.  
  97.         /*
  98.          * If there is only auto-indentation
  99.          * on the current line, delete it.
  100.          */
  101.         if (curpos->p_index == indentchars &&
  102.         cltext[indentchars] == '\0') {
  103.         replchars(curwin, curpos->p_line, 0, indentchars, "");
  104.         begin_line(curwin, FALSE);
  105.         }
  106.         indentchars = 0;
  107.  
  108.         /*
  109.          * The cursor should end up on the last inserted
  110.          * character. This is an attempt to match the real
  111.          * 'vi', but it may not be quite right yet.
  112.          */
  113.         while (one_left(curwin, FALSE) &&
  114.                 gchar(curwin->w_cursor) == '\0') {
  115.         ;
  116.         }
  117.  
  118.         State = NORMAL;
  119.  
  120.         end_command(curwin);
  121.  
  122.         (void) yank_str('<', flexgetstr(&Insbuff), FALSE);
  123.         flexclear(&Insbuff);
  124.  
  125.         if (!(echo & e_CHARUPDATE)) {
  126.         echo |= e_CHARUPDATE;
  127.         move_window_to_cursor(curwin);
  128.         cursupdate(curwin);
  129.         }
  130.         update_buffer(curbuf);
  131.         return(TRUE);
  132.     }
  133.  
  134.     case CTRL('T'):
  135.     case CTRL('D'):
  136.         /*
  137.          * If we're at the beginning of the line, or just
  138.          * after autoindent characters, move one shiftwidth
  139.          * left (CTRL('D')) or right (CTRL('T')).
  140.          */
  141.         if (curpos->p_index <= indentchars) {
  142.         Line    *lp;
  143.         int    ind;
  144.  
  145.         lp = curpos->p_line;
  146.         ind = get_indent(curpos->p_line);
  147.         ind += (c == CTRL('D') ? (ind < Pn(P_shiftwidth) ?
  148.                          -ind :
  149.                          -Pn(P_shiftwidth)) :
  150.                     Pn(P_shiftwidth));
  151.         indentchars = set_indent(lp, ind);
  152.         move_cursor(curwin, curpos->p_line, indentchars);
  153.         cursupdate(curwin);
  154.         updateline(curwin);
  155.         (void) flexaddch(&Insbuff, c);
  156.         } else {
  157.         beep(curwin);
  158.         }
  159.         return(TRUE);
  160.  
  161.     case '\b':
  162.     case DEL:
  163.         /*
  164.          * Can't backup past starting point.
  165.          */
  166.         if (curpos->p_line == Insertloc.p_line &&
  167.                 curpos->p_index <= Insertloc.p_index) {
  168.         beep(curwin);
  169.         return(TRUE);
  170.         }
  171.  
  172.         /*
  173.          * Can't backup to a previous line.
  174.          */
  175.         if (curpos->p_line != Insertloc.p_line && curpos->p_index <= 0) {
  176.         beep(curwin);
  177.         return(TRUE);
  178.         }
  179.         (void) one_left(curwin, FALSE);
  180.         if (curpos->p_index < indentchars)
  181.         indentchars--;
  182.         replchars(curwin, curpos->p_line, curpos->p_index, 1, "");
  183.         (void) flexaddch(&Insbuff, '\b');
  184.         cursupdate(curwin);
  185.         if (curwin->w_col == 0) {
  186.         /*
  187.          * Make sure backspacing over a physical line
  188.          * break updates the screen correctly.
  189.          */
  190.         update_buffer(curbuf);
  191.         } else {
  192.         updateline(curwin);
  193.         }
  194.         return(TRUE);
  195.  
  196.     case '\r':
  197.     case '\n':
  198.         {
  199.         int    i;
  200.         int    previndex;
  201.         Line    *prevline;
  202.  
  203.         (void) flexaddch(&Insbuff, '\n');
  204.  
  205.         i = indentchars;
  206.         prevline = curpos->p_line;
  207.         previndex = curpos->p_index;
  208.  
  209.         if (openfwd(TRUE) == FALSE) {
  210.             stuff("%c", ESC);
  211.             show_error(curwin,
  212.                 "No buffer space - returning to command mode");
  213.             return(TRUE);
  214.         }
  215.  
  216.         /*
  217.          * If the previous line only had
  218.          * auto-indent on it, delete it.
  219.          */
  220.         if (i == previndex) {
  221.             replchars(curwin, prevline, 0, i, "");
  222.         }
  223.  
  224.         move_window_to_cursor(curwin);
  225.         cursupdate(curwin);
  226.         update_buffer(curbuf);
  227.         }
  228.         return(TRUE);
  229.  
  230.     case CTRL('B'):
  231.         wait_buffer = TRUE;
  232.         return(FALSE);
  233.         break;
  234.  
  235.     case CTRL('V'):
  236.         (void) flexaddch(&Insbuff, CTRL('V'));
  237.         literal_next = TRUE;
  238.         return(FALSE);
  239.     }
  240.     }
  241.  
  242.     /*
  243.      * If we get here, we want to insert the character into the buffer.
  244.      */
  245.  
  246.     /*
  247.      * We may already have been in literal-next mode.
  248.      * Careful not to reset this until after we need it.
  249.      */
  250.     literal_next = FALSE;
  251.  
  252.     /*
  253.      * Deal with wrapmargin.
  254.      *
  255.      * OK, so it isn't really right yet.
  256.      */
  257.     if ((c == ' ' || c == '\t') && Pn(P_wrapmargin) != 0 &&
  258.     curwin->w_cursor->p_index >= curwin->w_ncols - Pn(P_wrapmargin)) {
  259.     (void) i_proc('\n');
  260.     /*
  261.      * We shouldn't really be putting the newline
  262.      * in the redo buffer, so we change it to the
  263.      * character we actually got.
  264.      */
  265.     flexrmchar(&Insbuff);
  266.     (void) flexaddch(&Insbuff, c);
  267.     return(TRUE);
  268.     }
  269.  
  270.     /*
  271.      * Do the actual insertion of the new character.
  272.      */
  273.     replchars(curwin, curpos->p_line, curpos->p_index, 0, mkstr(c));
  274.  
  275.     /*
  276.      * Update the screen.
  277.      */
  278.     s_inschar(curwin, c);
  279.     updateline(curwin);
  280.  
  281.     /*
  282.      * Put the character into the insert buffer.
  283.      */
  284.     (void) flexaddch(&Insbuff, c);
  285.  
  286.     /*
  287.      * If showmatch mode is set, check for right parens
  288.      * and braces. If there isn't a match, then beep.
  289.      * If there is a match AND it's on the screen,
  290.      * flash to it briefly.
  291.      *
  292.      * These characters included to make this
  293.      * source file work okay with showmatch: [ { (
  294.      */
  295.     if (Pb(P_showmatch) && (c == ')' || c == '}' || c == ']')) {
  296.     Posn    *lpos, csave;
  297.  
  298.     lpos = showmatch();
  299.     if (lpos == NULL) {
  300.         beep(curwin);
  301.     } else if (!earlier(lpos->p_line, curwin->w_topline) &&
  302.                earlier(lpos->p_line, curwin->w_botline)) {
  303.         /*
  304.          * Show the match if it's on screen.
  305.          */
  306.         update_buffer(curbuf);
  307.  
  308.         csave = *curpos;
  309.         move_cursor(curwin, lpos->p_line, lpos->p_index);
  310.         cursupdate(curwin);
  311.         wind_goto(curwin);
  312.  
  313.         delay();
  314.  
  315.         move_cursor(curwin, csave.p_line, csave.p_index);
  316.         cursupdate(curwin);
  317.     }
  318.     }
  319.  
  320.     /*
  321.      * Finally, move the cursor right one space.
  322.      */
  323.     (void) one_right(curwin, TRUE);
  324.  
  325.     return(TRUE);
  326. }
  327.  
  328. /*
  329.  * This function is the interface provided for functions in
  330.  * normal mode to go into insert mode. We only come out of
  331.  * insert mode when the user presses escape.
  332.  *
  333.  * The parameter is a flag to say whether we should start
  334.  * at the start of the line.
  335.  *
  336.  * Note that we do not have to call start_command() as the
  337.  * caller does that for us - this is so the caller can include
  338.  * any other stuff (e.g. an initial delete) into the command.
  339.  */
  340. void
  341. startinsert(startln)
  342. int    startln;    /* if set, insert point really at start of line */
  343. {
  344.     Insertloc = *curwin->w_cursor;
  345.     if (startln)
  346.     Insertloc.p_index = 0;
  347.     flexclear(&Insbuff);
  348.     State = INSERT;
  349. }
  350.  
  351. /*
  352.  * Process the given character, in replace mode.
  353.  */
  354. bool_t
  355. r_proc(c)
  356. int    c;
  357. {
  358.     Posn        *curpos;
  359.     static bool_t    literal_next = FALSE;
  360.     static bool_t    wait_buffer = FALSE;
  361.  
  362.     curpos = curwin->w_cursor;
  363.  
  364.     if (wait_buffer || (!literal_next && c == CTRL('A'))) {
  365.     /*
  366.      * Add contents of named buffer, or the last
  367.      * insert buffer if CTRL('A') was typed.
  368.      */
  369.     if (!wait_buffer) {
  370.         c = '<';
  371.     }
  372.     yp_stuff_input(curwin, c, TRUE);
  373.     wait_buffer = FALSE;
  374.     return(FALSE);
  375.  
  376.     } else if (!literal_next) {
  377.     switch (c) {
  378.     case ESC:            /* an escape ends input mode */
  379.         end_replace(c);
  380.         return(TRUE);
  381.  
  382.     case '\b':            /* back space */
  383.     case DEL:
  384.         if (repstate == overwrite &&
  385.         curwin->w_virtcol > start_column) {
  386.         (void) one_left(curwin, FALSE);
  387.         replchars(curwin, curpos->p_line,
  388.                 curpos->p_index, 1,
  389.                 (curpos->p_index < nchars) ?
  390.                 mkstr(saved_line[curpos->p_index]) : "");
  391.         updateline(curwin);
  392.         (void) flexaddch(&Insbuff, '\b');
  393.         } else {
  394.         beep(curwin);
  395.         if (repstate == replace_one) {
  396.             end_replace(c);
  397.         }
  398.         }
  399.         return(TRUE);
  400.  
  401.     case K_LARROW:            /* left arrow */
  402.         if (repstate == overwrite && curwin->w_virtcol > start_column &&
  403.                         one_left(curwin, FALSE)) {
  404.         (void) flexaddch(&Insbuff, c);
  405.         return(TRUE);
  406.         } else {
  407.         beep(curwin);
  408.         if (repstate == replace_one) {
  409.             end_replace(c);
  410.         }
  411.         return(FALSE);
  412.         }
  413.  
  414.     case K_RARROW:            /* right arrow */
  415.         if (repstate == overwrite && one_right(curwin, FALSE)) {
  416.         (void) flexaddch(&Insbuff, c);
  417.         return(TRUE);
  418.         } else {
  419.         beep(curwin);
  420.         if (repstate == replace_one) {
  421.             end_replace(c);
  422.         }
  423.         return(FALSE);
  424.         }
  425.  
  426.     case '\r':            /* new line */
  427.     case '\n':    
  428.         if (curpos->p_line->l_next == curbuf->b_lastline &&
  429.                         repstate == overwrite) {
  430.         /*
  431.          * Don't allow splitting of last line of
  432.          * buffer in overwrite mode. Why not?
  433.          */
  434.         beep(curwin);
  435.         return(TRUE);
  436.         }
  437.  
  438.         if (repstate == replace_one) {
  439.         echo &= ~e_CHARUPDATE;
  440.         if (openfwd(TRUE) == FALSE) {
  441.             show_error(curwin, "No buffer space!");
  442.             return(TRUE);
  443.         }
  444.  
  445.         (void) flexaddch(&Insbuff, c);
  446.  
  447.         /*
  448.          * Having split the line, we must
  449.          * delete the character which was
  450.          * supposed to be replaced with
  451.          * the newline.
  452.          */
  453.         replchars(curwin, curpos->p_line, curpos->p_index, 1, "");
  454.         repstate = got_one;
  455.         end_replace('\n');
  456.  
  457.         } else {
  458.         (void) flexaddch(&Insbuff, '\n');
  459.  
  460.         (void) onedown(curwin, 1L);
  461.  
  462.         /*
  463.          * This is wrong, but it's difficult
  464.          * to get it right.
  465.          */
  466.         coladvance(curwin, start_column);
  467.  
  468.         free(saved_line);
  469.         saved_line = strsave(curpos->p_line->l_text);
  470.         if (saved_line == NULL) {
  471.             State = NORMAL;
  472.             return(TRUE);
  473.         }
  474.         nchars = strlen(saved_line);
  475.         }
  476.  
  477.         return(TRUE);
  478.  
  479.     case CTRL('B'):
  480.         wait_buffer = TRUE;
  481.         return(FALSE);
  482.         break;
  483.  
  484.     case CTRL('V'):    
  485.         (void) flexaddch(&Insbuff, CTRL('V'));
  486.         literal_next = TRUE;
  487.         return(TRUE);
  488.     }
  489.     }
  490.  
  491.     /*
  492.      * If we get here, we want to insert the character into the buffer.
  493.      */
  494.  
  495.     /*
  496.      * We may already have been in literal-next mode.
  497.      * Careful not to reset this until after we need it.
  498.      */
  499.     literal_next = FALSE;
  500.  
  501.     /*
  502.      * Put the character into the insert buffer.
  503.      */
  504.     (void) flexaddch(&Insbuff, c);
  505.  
  506.     if (repstate == overwrite || repstate == replace_one) {
  507.     replchars(curwin, curpos->p_line, curpos->p_index, 1, mkstr(c));
  508.     updateline(curwin);
  509.     (void) one_right(curwin, TRUE);
  510.     }
  511.  
  512.     /*
  513.      * If command was an 'r', leave replace mode after one character.
  514.      */
  515.     if (repstate == replace_one) {
  516.     repstate = got_one;
  517.     end_replace(c);
  518.     }
  519.  
  520.     return(TRUE);
  521. }
  522.  
  523. /*
  524.  * This function is the interface provided for functions in
  525.  * normal mode to go into replace mode. We only come out of
  526.  * replace mode when the user presses escape, or when they
  527.  * used the 'r' command and typed a single character.
  528.  *
  529.  * The parameter is the command character which took us into replace mode.
  530.  */
  531. void
  532. startreplace(c)
  533. int    c;
  534. {
  535.     if (!start_command(curwin)) {
  536.     return;
  537.     }
  538.     start_index = curwin->w_cursor->p_index;
  539.     start_column = curwin->w_virtcol;
  540.  
  541.     if (c == 'r') {
  542.     repstate = replace_one;
  543.     saved_line = NULL;
  544.     } else {
  545.     repstate = overwrite;
  546.     saved_line = strsave(curwin->w_cursor->p_line->l_text);
  547.     if (saved_line == NULL) {
  548.         beep(curwin);
  549.         end_command(curwin);
  550.         return;
  551.     }
  552.     nchars = strlen(saved_line);
  553.  
  554.     /*
  555.      * Initialize Insbuff. Note that we don't do this if the
  556.      * command was 'r', because they might type ESC to abort
  557.      * the command, in which case we shouldn't change Insbuff.
  558.      */
  559.     flexclear(&Insbuff);
  560.  
  561.     }
  562.     State = REPLACE;
  563. }
  564.  
  565. static void
  566. end_replace(c)
  567.     int    c;
  568. {
  569.     Posn    *curpos;
  570.     char    *cltext;
  571.  
  572.     curpos = curwin->w_cursor;
  573.  
  574.     State = NORMAL;
  575.     end_command(curwin);
  576.  
  577.     /*
  578.      * If (repstate == replace_one), they must have typed 'r', then
  579.      * thought better of it & typed ESC; so we shouldn't complain or
  580.      * change the buffer, the cursor position, or Insbuff.
  581.      */
  582.     if (repstate != replace_one) {
  583.  
  584.     (void) yank_str('<', flexgetstr(&Insbuff), FALSE);
  585.     flexclear(&Insbuff);
  586.  
  587.     /*
  588.      * Free the saved line if necessary.
  589.      */
  590.     if (repstate == overwrite) {
  591.         free(saved_line);
  592.     }
  593.  
  594.     /*
  595.      * The cursor should end up on the
  596.      * last replaced character.
  597.      */
  598.     cltext = curpos->p_line->l_text;
  599.     while (one_left(curwin, FALSE) && gchar(curwin->w_cursor) == '\0') {
  600.         ;
  601.     }
  602.  
  603.     if (!(echo & e_CHARUPDATE)) {
  604.         echo |= e_CHARUPDATE;
  605.         move_window_to_cursor(curwin);
  606.         cursupdate(curwin);
  607.     }
  608.     update_buffer(curbuf);
  609.     }
  610. }
  611.  
  612. char *
  613. mkstr(c)
  614. int    c;
  615. {
  616.     static    char    s[2];
  617.  
  618.     s[0] = c;
  619.     s[1] = '\0';
  620.  
  621.     return(s);
  622. }
  623.